// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package noder

import (
	"bytes"
	"fmt"
	"io"

	"cmd/compile/internal/base"
	"cmd/compile/internal/typecheck"
	"cmd/internal/bio"
)

// writeNewExportFunc是一个可以添加的钩子，用于在正常导出数据部分之后附加额外的
// 导出数据。它允许
// 试验新的导出数据格式设计，而无需
// 在go/internal或x/tools导入程序中立即提供支持。
var writeNewExportFunc func(out io.Writer)

func WriteExports(out *bio.Writer) {
	// 启用统一IR导出后，我们只需将其附加到正常导出数据的
	// 末尾（禁用编译器扩展
	// ），并写入一个额外的头，给出其大小。
	// 
	// 如果编译器看到这个头，它知道读取新数据
	// 而不是；与此同时，go/types进口商将默默地忽略它
	// 并继续处理旧的出口。
	// 
	// 这使我们可以尝试更改新的导出数据
	// 格式，而无需更新go/internal/gcimporter或
	// （更糟）x/tools/go/gcexportdata。

	useNewExport := writeNewExportFunc != nil

	var old, new bytes.Buffer

	typecheck.WriteExports(&old, !useNewExport)

	if useNewExport {
		writeNewExportFunc(&new)
	}

	oldLen := old.Len()
	newLen := new.Len()

	if useNewExport {
		fmt.Fprintf(out, "\nnewexportsize %v\n", newLen)
	}

	// 链接器也会查找$$标记-在$$之后使用char来区分格式。
	out.WriteString("\n$$B\n") // 表示二进制导出格式
	io.Copy(out, &old)
	out.WriteString("\n$$\n")
	io.Copy(out, &new)

	if base.Debug.Export != 0 {
		fmt.Printf("BenchmarkExportSize:%s 1 %d bytes\n", base.Ctxt.Pkgpath, oldLen)
		if useNewExport {
			fmt.Printf("BenchmarkNewExportSize:%s 1 %d bytes\n", base.Ctxt.Pkgpath, newLen)
		}
	}
}
